package com.kaoker.system.dao.util;

import javax.naming.InitialContext;
import javax.naming.NamingException;

import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.Environment;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Hibernate Util Class.
 * 
 * @author bladestone
 *
 */
public class HibernateUtil {
	private static Configuration configuration;
	private static SessionFactory sessionFactory;
	private static final Logger logger = LoggerFactory.getLogger(HibernateUtil.class);
	
	static {
		configuration = new Configuration();
		configuration.configure();
		
//		if (configuration.getProperty(Environment.SESSION_FACTORY_NAME) != null) {
//            // Let Hibernate bind the factory to JNDI
//            configuration.buildSessionFactory();
//        } else {
            // or use static variable handling
            sessionFactory = configuration.buildSessionFactory();
       // }
	}
	 
	/**
     * Returns the original Hibernate configuration.
     *
     * @return Configuration
     */
    public static Configuration getConfiguration() {
        return configuration;
    }

    /**
     * Returns the global SessionFactory.
     *
     * @return SessionFactory
     */
    public static SessionFactory getSessionFactory() {
//        SessionFactory sf = null;
//        String sfName = configuration.getProperty(Environment.SESSION_FACTORY_NAME);
//        if ( sfName != null) {
//            logger.debug("Looking up SessionFactory in JNDI.");
//            try {
//                sf = (SessionFactory) new InitialContext().lookup(sfName);
//            } catch (NamingException ex) {
//                throw new RuntimeException(ex);
//            }
//        } else {
//            sf = sessionFactory;
//        }
//        if (sf == null)
//            throw new IllegalStateException("SessionFactory not available.");
        return sessionFactory;
    }
    
    /**
     * Closes the current SessionFactory and releases all resources.
     * <p>
     * The only other method that can be called on HibernateUtil
     * after this one is rebuildSessionFactory(Configuration).
     */
    public static void shutdown() {
        logger.debug("Shutting down Hibernate.");
        // Close caches and connection pools
        getSessionFactory().close();

        // Clear static variables
        configuration = null;
        sessionFactory = null;
    }


    /**
     * Rebuild the SessionFactory with the static Configuration.
     * <p>
     * This method also closes the old SessionFactory before, if still open.
     * Note that this method should only be used with static SessionFactory
     * management, not with JNDI or any other external registry.
     */
     public static void rebuildSessionFactory() {
        logger.debug("Using current Configuration for rebuild.");
        rebuildSessionFactory(configuration);
     }

    /**
     * Rebuild the SessionFactory with the given Hibernate Configuration.
     * <p>
     * HibernateUtil does not configure() the given Configuration object,
     * it directly calls buildSessionFactory(). This method also closes
     * the old SessionFactory before, if still open.
     *
     * @param cfg
     */
     public static void rebuildSessionFactory(Configuration cfg) {
        logger.debug("Rebuilding the SessionFactory from given Configuration.");
        synchronized(sessionFactory) {
            if (sessionFactory != null && !sessionFactory.isClosed())
                sessionFactory.close();
            if (cfg.getProperty(Environment.SESSION_FACTORY_NAME) != null)
                cfg.buildSessionFactory();
            else
                sessionFactory = cfg.buildSessionFactory();
            configuration = cfg;
        }
     }
}
